/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package snAnalysis;

import java.io.DataInputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;

/**
 *
 * @author FUJISAI
 */
public class Filter implements Comparator {

    private ArrayList<String> PCList;
    private String method;
    private ArrayList<String> anchors;
    private ArrayList<String> blogIDList;

    public Filter(String method) {
        this.method = method;
        if (method.compareTo("dbSorting") == 0) {
            this.PCList = new ArrayList<String>();
            this.anchors = new ArrayList<String>();
            this.blogIDList = new ArrayList<String>();
            this.setPCList();
            this.setAnchors();
        } else if (method.compareTo("chordBased") == 0) {
            this.PCList = new ArrayList<String>();
            this.setPCList();
        }
    }

    public final int compare(Object a, Object b) {
        String aStr = this.getMD5HexCode(a.toString());
        String bStr = this.getMD5HexCode(b.toString());
        return (aStr.compareTo(bStr));
    }

    private void setPCList() {
        String path = "";

        SNALib bfl = new SNALib();
        if (bfl.getOSName().compareToIgnoreCase("windows") == 0) {
            path = Configuration.getValue("windowsPath", "D:\\");
        } else {
            path = Configuration.getValue("linuxPath", "/root/");
        }
        String file_name = Configuration.getValue("pc_list_file", "PCList.txt");

        try {
            FileInputStream fin = new FileInputStream(path + file_name);
            DataInputStream din = new DataInputStream(fin);

            while (din.available() != 0) {
                String temp = din.readLine();
                if (temp.compareTo("") != 0) {
                    this.PCList.add(temp);
                }
            }
            din.close();
            fin.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException ioe) {
            ioe.printStackTrace();
        }
        Collections.sort(this.PCList, this);
    }

    public ArrayList getPCList() {
        return this.PCList;
    }

    /**
     *
     * @param document input document that need to make MD5HexCode
     * @return MD5HexCode of input document
     */
    private String getMD5HexCode(String document) {
        try {
            MessageDigest m = MessageDigest.getInstance("MD5");

            m.update(document.getBytes(), 0, document.length());

            String hashCode = new BigInteger(1, m.digest()).toString(16);
            if (hashCode.length() == 31) {
                hashCode = "0" + hashCode;
            }

            return hashCode;
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }

        return null;
    }

    /**
     * 
     * @param doc_hash
     * @return IP address of Machine to send document
     */
    private String compareHashCode(String input) {
        String doc_hash = this.getMD5HexCode(input);
        for (int i = 0; i < this.PCList.size(); i++) {
            int value = doc_hash.compareTo(this.getMD5HexCode(this.PCList.get(i).toString()));
            if (value < 0) {
                return this.PCList.get(i).toString();
            }
        }
        return this.PCList.get(0).toString(); // Return first machine to store info
    }

    /**
     * Start of another FILTER for FIXED Database, FIXED PC quantity
     * This FILTER based on sorting the database, then divide the sorted-DB
     * into the numbers of PCs pieces. Then it save the "point" that divide
     * the database to make further decision.
     */
    public ArrayList getAnchors() {
        return this.anchors;
    }

    private void setAnchors() {
        MySQLBridge ms = new MySQLBridge();

        String tb_name = Configuration.getValue("table_name", "blog_list");

        try {
            int list_size = 0;
            ResultSet total = ms.customQuery("SELECT COUNT(*) AS TOTAL FROM `" + tb_name + "`");
            while (total.next()) {
                list_size = total.getInt("TOTAL");
            }
            ResultSet list = ms.getSingleField(tb_name, "blogID", "1 ORDER BY `blogID`");
            while (list.next()) {
                this.blogIDList.add(list.getString("blogID"));
            }
            Collections.sort(this.blogIDList);

            int pc_size     = PCList.size();
            int blog_size   = this.blogIDList.size();
            if (PCList.size() > 1) {
                int chia = blog_size / pc_size;
                for (int i=1; i< pc_size; i++) {
                    this.anchors.add(this.blogIDList.get(i*chia));
                }
            }
            this.anchors.add(this.blogIDList.get(blog_size-1));
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

    private String compareWithAnchors(String input) {
        for (int i=0;i<this.anchors.size();i++) {
            if (input.compareTo(this.anchors.get(i)) <= 0 ) {
                return this.PCList.get(i);
            }
        }
        return "";
    }
    /**
     * Get the output IP address based on filter method used
     * @param input
     * @return
     */
    public String getOutputIP(String input) {
        if (this.method.compareTo("dbSorting") == 0) {
            return this.compareWithAnchors(input);
        } else if (this.method.compareTo("chordBased") == 0) {
            return this.compareHashCode(input);
        }
        return "";
    }
}
